<script setup lang="ts">
import { onMounted, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import Guacamole from 'guacamole-common-js'
import { VCMsgForOpenApp, noticeInsertOpenAppLogs, noticeBindWinSessionId } from './guacd_code'
import { getLinkDetail } from '@/api/cap'

const desktopObj = {
  client: undefined,
  layer: undefined,
  state: 0,
  sink: undefined,
}
const getQueryParams = (url: string) => {
  const paramArr = url.slice(url.indexOf('?') + 1).split('&')
  const params = new Map()
  paramArr.map((param) => {
    const [key, val] = param.split('=')
    params.set(key, decodeURIComponent(val))
  })
  return params
}

onMounted(() => {
  wsHandshake()
})
const wsHandshake = () => {
  const param = getQueryParams(window.location.href)
  console.log(param)
  const width = document.body.clientWidth - 1
  const height = document.body.clientHeight
  const params =
    'linkId=' +
    param.get('linkId') +
    '&sessionId=' +
    param.get('sessionId') +
    '&width=' +
    width +
    '&height=' +
    height
  const linkDetail = getLinkDetail(param.get('linkId'))
  linkDetail.then((res) => {
    if (res.protocol == 'cap') {
      openFullScreen()
    }
  })

  const websocketPath = `ws://${window.location.hostname}:${window.location.port}/api/cap/session/conn`

  // const websocketPath = 'ws://localhost:19003/api/cap/session/conn'
  const tunnel = new Guacamole.WebSocketTunnel(websocketPath)
  console.log(websocketPath, tunnel)
  // 创建桌面客户端
  desktopObj.client = new Guacamole.Client(tunnel)
  // 解析自定义指令，这行代码必须放到  new Guacamole.Client(tunnel) 代码之后
  const _oninstruction = tunnel.oninstruction
  tunnel.oninstruction = (opcode, parameters) => {
    onTunnelInstruction(opcode, parameters)
    if (_oninstruction) {
      _oninstruction(opcode, parameters)
    }
  }
  desktopObj.client.onerror = onClientError
  // 处理客户端的状态变化事件
  desktopObj.client.onstatechange = onClientStateChange
  desktopObj.client.onpipe = onPipe

  const display = document.getElementById('display')
  desktopObj.layer = desktopObj.client.getDisplay()
  const element = desktopObj.client.getDisplay().getElement()
  display.appendChild(element)
  desktopObj.client.connect(params)
  // 页面关闭时销毁客户端对象
  window.onunload = function () {
    desktopObj.client.disconnect()
  }

  // mouse
  const mouse = new Guacamole.Mouse(element)
  mouse.onmousedown =
    mouse.onmouseup =
    mouse.onmousemove =
      function (mouseState: any) {
        const ms = new Guacamole.Mouse.State(
          mouseState.x / desktopObj.layer.getScale(),
          mouseState.y / desktopObj.layer.getScale(),
          mouseState.left,
          mouseState.middle,
          mouseState.right,
          mouseState.up,
          mouseState.down,
        )
        desktopObj.client.sendMouseState(ms)
      }
  // sink
  desktopObj.sink = new Guacamole.InputSink()
  display.appendChild(desktopObj.sink.getElement())
  desktopObj.sink.focus()

  // Keyboard
  const keyboard = new Guacamole.Keyboard(desktopObj.sink.getElement())
  keyboard.onkeydown = onKeyDown
  keyboard.onkeyup = onKeyUp
}

const onKeyUp = (keySym) => {
  desktopObj.client.sendKeyEvent(0, keySym)
}
const onKeyDown = (keySym) => {
  console.log(keySym)
  desktopObj.client.sendKeyEvent(1, keySym)
  if (keySym === 65288) {
    return false
  }
}
const onTunnelInstruction = (opcode: any, parameters: any) => {
  if (opcode == 'disconnect') {
    console.log('连接销毁，画面关闭')
  }
  if (opcode == 'error') {
    console.error('指令', opcode, '参数', parameters)
    desktopObj.client.disconnect()
  }
}

const onClientError = (state: any) => {
  console.log('onClientError', state)
}
const onClientStateChange = (state: any) => {
  console.log('onClientStateChange', state)
  // const param = getQueryParams(window.location.href)
}
const onPipe = (input, mimetype, name) => {
  console.log('onPipe >>', input, mimetype, name)
  if (name !== 'LAUNCH') {
    return
  }
  const reader = new Guacamole.StringReader(input)
  reader.ontext = function (text) {
    try {
      console.log(text)
      const vmsg = JSON.parse(text)
      // const param = getQueryParams(window.location.href)
      // let data5: any = {}
      switch (vmsg.code) {
        // 打开通道后发送出去的第一个信号
        case 1:
          console.log('通知go绑定会话id，同时发送信号，打开应用', vmsg)
          noticeBindWinSessionId(vmsg.data)
          VCMsgForOpenApp(desktopObj)
          break
        case 3:
          ElMessage.error(vmsg.data)
          break
        case 4:
          ElMessage.error(vmsg.data)
          break
        // 打开应用成功
        case 5:
          console.log('打开应用成功，插入日志打开记录', vmsg)
          closeFullScreen()
          noticeInsertOpenAppLogs(vmsg.data)
          break
        default:
          console.log('未知的消息类型：', vmsg)
      }
    } catch (e) {
      console.log('解析LAUNCH参数失败', e)
    }
  }
}

const fullscreenLoading = ref(false)
const openFullScreen = () => {
  fullscreenLoading.value = true
}

const closeFullScreen = () => {
  fullscreenLoading.value = false
}
</script>

<template>
  <div v-loading.fullscreen.lock="fullscreenLoading">
    <div style="width: 96%; height: 96vh" id="display"></div>
  </div>
</template>

<style scoped></style>
